import os
import time
import socket
import base64
import requests
import cStringIO

from urlparse import urlparse

from app.exceptions import ProxyUsageImpossible
from core.models import Result

socket.setdefaulttimeout(120)

UNABLE_CONNECT_TO_HOST = -1
NO_CONTENT = '[NO_CONTENT]'

class Request:
    def __init__(self, proxy_info=None):
        self.proxy = proxy_info
        self.use_proxy = proxy_info['use']

    def perform(self, scan = None, schedule=None):
        # Set default opener
        self.set_opener()

        self.scan = scan

        proxy_headers, proxy_content = ('', '')
        ip_struct = self.get_ip(self.link.link.__str__())
        direct_headers, direct_content = self.request()

        if self.use_proxy:
            self.set_opener(self.proxy)
            proxy_headers, proxy_content = self.request()

        if len(ip_struct) < 1:
            ip_struct = [None, None, None]

        result = Result()

        result.scan = scan
        result.schedule = schedule
        result.aliaslist = str(ip_struct[1])
        result.ipaddrlist = str(ip_struct[2])
        result.link = self.link
        result.link_uri = self.link.link

        result.header = {
            'direct': direct_headers,
            'proxy': proxy_headers
        }

        result.screenshot = {}

        try:
            result.dump = {
                'direct': base64.encodestring(direct_content.getvalue()),
                'proxy': base64.encodestring(proxy_content.getvalue())
            }
        except AttributeError:
            result.dump = {
                'direct': '',
                'proxy': ''
            }

        result.save()

        time.sleep(1)

    def request(self, head=False):
        pass

    def get_ip(self, link=None):
        if link:
            parsed_url = urlparse(url=link)

            # gethostbyname_ex(host) -> (name, aliaslist, addresslist)
            # Return the true host name, a list of aliases, and a list of IP addresses, for a host.
            # The host argument is a string giving a host name or IP number.
            try:
                if parsed_url.netloc:
                    to_get = parsed_url.netloc
                elif parsed_url.path:
                    to_get = parsed_url.path

                return socket.gethostbyname_ex(to_get)
            except socket.gaierror:
                return []

    def set_uri(self, link=object):
        if link:
            if 'http://' not in link.link.lower():
                link.link = 'http://%s' % link.link

            self.link = link

    def set_opener(self, proxy=None):
        pass

class Requests(Request):
    def __init__(self, proxy_info=None):
        Request.__init__(self, proxy_info=proxy_info)

    # The actual request maker
    def request(self, head=False):
        headers = {}
        content = cStringIO.StringIO()

        try:
            if self.proxy_object:
                response = requests.get(url=self.link.link.__str__(),
                                        proxies={'http': self.proxy_object})
            else:
                response = requests.get(url=self.link.link.__str__())

            headers = response.headers

            if response.ok:
                headers.setdefault('status', response.status_code)

                if self.link.dump and head is False:
                    content.write(response.content)
                else:
                    content.write(NO_CONTENT)
            else:
                headers.setdefault('status', response.status_code)
                content.write(NO_CONTENT)
        except requests.HTTPError:
            return (
                headers.setdefault('status', UNABLE_CONNECT_TO_HOST),
                content.write(NO_CONTENT)
            )

        return headers, content

    # Builds opener
    def set_opener(self, proxy=None):
        if self.use_proxy and proxy:
            if not proxy['user'] or not proxy['password']:
                scheme = '%s://%s:%s' % (
                    'http',
                    proxy['host'],
                    proxy['port']
                )
            else:
                scheme = '%s://%s:%s@%s:%s' % (
                    'http',
                    proxy['user'],
                    proxy['password'],
                    proxy['host'],
                    proxy['port']
                )

            #print 'Setting proxy: ', scheme

            self.proxy_object = scheme

        elif not self.use_proxy and proxy:
            # if don't use proxy but proxy object was passed
            raise ProxyUsageImpossible('Unable to use proxy.')
        elif not proxy:
            #print 'Setting default opener'
            # if proxy is None the set default opener
            self.proxy_object = None
